home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / AppsToGo / Kibitz / AEchess.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-22  |  56.9 KB  |  1,920 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        aechess.c
  5. ** Written by:  Eric Soldan
  6. **
  7. ** Copyright © 1990-1992 Apple Computer, Inc.
  8. ** All rights reserved.
  9. **
  10. ** This is the custom AppleEvents code.  The required AppleEvents code is in
  11. ** the file AppleEvents.c, which is Keith Rollin's work. */
  12.  
  13.  
  14.  
  15. /*****************************************************************************/
  16.  
  17.  
  18.  
  19. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  20. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  21. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  22.  
  23. #ifndef __AEUTILS__
  24. #include <AEUtils.h>
  25. #endif
  26.  
  27. #ifndef __ERRORS__
  28. #include <Errors.h>
  29. #endif
  30.  
  31. #ifndef __FONTS__
  32. #include <Fonts.h>
  33. #endif
  34.  
  35. #ifndef __LOWMEM__
  36. #include <LowMem.h>
  37. #endif
  38.  
  39. #ifndef __MEMORY__
  40. #include <Memory.h>
  41. #endif
  42.  
  43. #ifndef __NOTIFICATION__
  44. #include <Notification.h>
  45. #endif
  46.  
  47. #ifndef __OSUTILS__
  48. #include <OSUtils.h>
  49. #endif
  50.  
  51. #ifndef __PPC__
  52. #include "PPC.h"
  53. #endif
  54.  
  55. #ifndef __RESOURCES__
  56. #include <Resources.h>
  57. #endif
  58.  
  59. #ifndef __SOUND__
  60. #include <Sound.h>
  61. #endif
  62.  
  63. #ifndef __TOOLUTILS__
  64. #include <ToolUtils.h>
  65. #endif
  66.  
  67. #ifndef __TEXTEDITCONTROL__
  68. #include <TextEditControl.h>
  69. #endif
  70.  
  71. #ifndef __UTILITIES__
  72. #include <Utilities.h>
  73. #endif
  74.  
  75.  
  76.  
  77. /*****************************************************************************/
  78.  
  79.  
  80.  
  81. #define PRIORITY        kAENormalPriority
  82. #define kTimeOutInTicks (60 * 30)    /* 30 second timeout. */
  83.  
  84.  
  85.  
  86. /*****************************************************************************/
  87.  
  88.  
  89.  
  90. static pascal void    CancelNotify(NMRecPtr nmReqPtr);
  91. static void            GetFullPathAndAppName(StringPtr path, StringPtr app);
  92.  
  93. static void            GetAppFullPath(StringPtr path);
  94.  
  95.  
  96.  
  97. /*****************************************************************************/
  98.  
  99.  
  100.  
  101. struct triplets{
  102.     AEEventClass        theEventClass;
  103.     AEEventID            theEventID;
  104.     ProcPtr                theHandler;
  105.     AEEventHandlerUPP    theUPP;
  106. };
  107. typedef struct triplets triplets;
  108. static triplets keywordsToInstall[] = {
  109.     { kCoreEventClass,        kAEAnswer,                (ProcPtr)DoAEAnswer,    nil },
  110.     { kCustomEventClass,    kibitzAESendGame,        (ProcPtr)ReceiveGame,    nil },
  111.     { kCustomEventClass,    kibitzAESendMssg,        (ProcPtr)ReceiveMssg,    nil }
  112. };        /* These are the custom AppleEvents. */
  113.  
  114.  
  115.  
  116. /*****************************************************************************/
  117.  
  118.  
  119.  
  120. extern Boolean        gHasAppleEvents;
  121. extern Boolean        gHasPPCToolbox;
  122.  
  123. extern RgnHandle    gCurrentCursorRgn;
  124. extern Cursor        *gCurrentCursor;
  125.  
  126. extern short        gMenuMods;
  127.  
  128.  
  129.  
  130. /*****************************************************************************/
  131. /*****************************************************************************/
  132.  
  133. #ifdef applec
  134. #pragma segment AppleEvents
  135. #endif
  136.  
  137. /*****************************************************************************/
  138. /*****************************************************************************/
  139.  
  140.  
  141.  
  142. /* InitCustomAppleEvents
  143. **
  144. ** Install our custom AppleEvents.  This is done in addition to installing
  145. ** the required AppleEvents.  InitAppleEvents, which installs the required
  146. ** AppleEvents, must be called first, since it sets up some global values. */
  147.  
  148. void    InitCustomAppleEvents(void)
  149. {
  150.     OSErr    err;
  151.     short    i;
  152.  
  153.     if (gHasAppleEvents) {
  154.         for (i = 0; i < (sizeof(keywordsToInstall) / sizeof(triplets)); ++i) {
  155.  
  156.             if (!keywordsToInstall[i].theUPP)
  157.                 keywordsToInstall[i].theUPP = NewAEEventHandlerProc(keywordsToInstall[i].theHandler);
  158.  
  159.             err = AEInstallEventHandler(
  160.                 keywordsToInstall[i].theEventClass,    /* What class to install.  */
  161.                 keywordsToInstall[i].theEventID,    /* Keywords to install.    */
  162.                 keywordsToInstall[i].theUPP,        /* The AppleEvent handler. */
  163.                 0L,                                    /* Unused refcon.           */
  164.                 false                                /* Only for our app.       */
  165.             );
  166.  
  167.             if (err) {
  168.                 Alert(rErrorAlert, gAlertFilterUPP);
  169.                 return;
  170.             }
  171.         }
  172.     }
  173. }
  174.  
  175.  
  176.  
  177. /*****************************************************************************/
  178.  
  179.  
  180.  
  181. pascal OSErr    DoAEAnswer(AppleEvent *message, AppleEvent *reply, long refcon)
  182. {
  183. #ifndef __MWERKS__
  184. #pragma unused (refcon)
  185. #endif
  186.  
  187.     OSErr    err;
  188.  
  189.     gCurrentCursor = nil;
  190.         /* Force re-calc of cursor region and cursor to use. */
  191.  
  192.     err = ReceiveGameReply(message, reply);
  193.  
  194.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  195.         reply,                    /* The AppleEvent.              */
  196.         keyReplyErr,            /* AEKeyword                 */
  197.         typeShortInteger,        /* Desired type.             */
  198.         (Ptr)&err,                /* Pointer to area for data. */ 
  199.         sizeof(short)            /* Size of data area.         */
  200.     );
  201.  
  202.     return(noErr);
  203. }
  204.  
  205.  
  206.  
  207. /*****************************************************************************/
  208.  
  209.  
  210.  
  211. /* SendGame
  212. **
  213. ** This routine acquires an opponent and sends the opponent the current game.
  214. ** Various changes are made to the game record to indicate that this game
  215. ** has an opponent, which color we are, where we are located (so the
  216. ** opponent can send moves back), the ID of our game, etc.  Once this
  217. ** information is in the game record, the game is transmitted to the
  218. ** opponent.  Upon receiving the game, the opponent sends back confirmation,
  219. ** which also includes the ID of the game on the opponent's end.  The return
  220. ** information is sent back as via AEAnswer, so we will extablish a two-player
  221. ** game until we receive this event.  Once we do establish a two-player game,
  222. ** we will store the opponent's game ID in the game record as well.  With our
  223. ** ID and the opponents ID, we will be able to determine which game the data
  224. ** is for at both ends.  This allows two opponents to play multiple games with
  225. ** the same machines. */
  226.  
  227. void    TogglePPCPatches(Boolean on);
  228.  
  229. OSErr    SendGame(FileRecHndl frHndl, short sendReason, StringPtr nbpType)
  230. {
  231.     AEAddressDesc    locOfOpponent;
  232.     Boolean            twoPlayer;
  233.     OSErr            err;
  234.     AEDescList        sendGameList;
  235.     long            gameID[2], size, timeout;
  236.     char            hstate;
  237.     Ptr                ptr1, ptr2;
  238.     GameListHndl    gameMoves;
  239.     AppleEvent        theAevt, reply;
  240.     short            replyType;
  241.     Str255            macText, appText, opponentName, reconnectPath;
  242.     Str32            reconnectApp;
  243.     Handle            userNameHndl;
  244.     static PPCFilterUPP    kibitzPortFilterUPP;
  245.  
  246.     sendGameList.dataHandle = theAevt.dataHandle = reply.dataHandle = nil;
  247.         /* Make sure disposing of the descriptors is okay in all cases.
  248.         ** This will not be necessary after 7.0b3, since the calls that
  249.         ** attempt to create the descriptors will nil automatically
  250.         ** upon failure. */
  251.  
  252.     err = noErr;
  253.         /* We may not make the first operation that can cause an error,
  254.         ** so we have to initialize err. */
  255.  
  256.     locOfOpponent.dataHandle = nil;
  257.         /* Make it safe to dispose of in all cases. */
  258.  
  259.     if ((*frHndl)->doc.resync < ((*frHndl)->doc.sendReason = sendReason))
  260.         (*frHndl)->doc.resync = sendReason;
  261.             /* Bump up resync, if needed. */
  262.  
  263.     UpdateTime(frHndl, false);
  264.         /* Make sure timers are current before we give them to opponent. */
  265.  
  266.     twoPlayer = (*frHndl)->doc.twoPlayer;
  267.     if (!twoPlayer) {            /* If we don't have a live opponent yet... */
  268.         GetIndString(macText, rPPCText, sTitleText);
  269.         GetIndString(appText, rPPCText, sAppText);
  270.  
  271.         if ((*frHndl)->doc.reconnectZone[0]) {
  272.             for (timeout = TickCount() + 600; timeout > TickCount();) {
  273.                 err = GetRemoteProcessTarget(frHndl, &locOfOpponent, KibitzFilter);
  274.                 if (err) break;
  275.                 if (locOfOpponent.dataHandle) break;
  276.             }
  277.         }
  278.         else {
  279. #ifndef powerc
  280.             if (gMenuMods & shiftKey) TogglePPCPatches(true);
  281. #endif
  282.             if (!kibitzPortFilterUPP)
  283.                 kibitzPortFilterUPP = NewPPCFilterProc (KibitzPortFilter);
  284.             err = MakeTarget(&locOfOpponent, false, kAEWaitReply,
  285.                 macText, appText, kibitzPortFilterUPP, (char *)nbpType);
  286.                     /* Generate the target for our opponent. */
  287. #ifndef powerc
  288.             if (gMenuMods & shiftKey) TogglePPCPatches(false);
  289. #endif
  290.         }
  291.  
  292.         (*frHndl)->doc.gameID_0      = gameID[0] = (TickCount() & 0xFFFFFFFE);
  293.         (*frHndl)->doc.gameID_1      = gameID[0];
  294.         (*frHndl)->doc.locOfOpponent = locOfOpponent;
  295.     }
  296.     else locOfOpponent = (*frHndl)->doc.locOfOpponent;
  297.  
  298.     if (!err) {        /* If we have an opponent... */
  299.         err = AECreateList(        /* CREATE THE LIST TO HOLD THE GAME. */
  300.             nil,                /* No factoring.             */
  301.             0,                    /* No factoring.             */
  302.             false,                /* Not an AppleEvent record. */
  303.             &sendGameList        /* List descriptor.             */
  304.         );
  305.     }
  306.  
  307.     if (!err) {        /* If we have an empty list to add to... */
  308.         hstate = LockHandleHigh((Handle)frHndl);
  309.         ptr1   = (Ptr)&((*frHndl)->doc);
  310.         ptr2   = (Ptr)&((*frHndl)->doc.endSendInfo);
  311.         size   = (long)ptr2 - (long)ptr1;
  312.         err = AEPutPtr(        /* ADD BOARD INFO TO THE APPLEEVENT. */
  313.             &sendGameList,    /* List to add to.                     */
  314.             1L,                /* Make this element #1.             */
  315.             typeTheBoard,    /* It is a descriptor for the board. */
  316.             ptr1,            /* Pointer to the board data.         */
  317.             size            /* Size of the board data.             */
  318.         );
  319.         HSetState((Handle)frHndl, hstate);
  320.     }
  321.  
  322.     /* For a new opponent, the field twoPlayer in sendGameList (to be sent
  323.     ** to the opponent) indicates that there is no live opponent.  When the
  324.     ** receiver gets a board with twoPlayer false, this indicates a new game
  325.     ** is being set up.  If twoPlayer is true, then it is an existing game. */
  326.  
  327.     if (!err) {        /* If we could add the board info to the list... */
  328.         gameMoves = (*frHndl)->doc.gameMoves;
  329.         size      = (*frHndl)->doc.numGameMoves * sizeof(GameElement);
  330.         hstate    = LockHandleHigh((Handle)gameMoves);
  331.         err = AEPutPtr(            /* ADD GAME MOVES TO THE LIST.             */
  332.             &sendGameList,        /* List to add to.                         */
  333.             2L,                    /* Make this element #2.                 */
  334.             typeGameMoves,        /* Descriptor for the moves of the game. */
  335.             (Ptr)(*gameMoves),    /* Pointer to the move data.             */
  336.             size                /* Size of the move data.                 */
  337.         );
  338.         HSetState((Handle)gameMoves, hstate);
  339.     }
  340.  
  341.     if ((!err) && (!twoPlayer)) {
  342.         hstate = LockHandleHigh((Handle)frHndl);
  343.         ptr1   = (Ptr)&((*frHndl)->fileState.fss);
  344.         err = AEPutPtr(            /* ADD FSSpec TO LIST TO PASS THE GAME NAME. */
  345.             &sendGameList,        /* List to add to.         */
  346.             3L,                    /* Make this element #3. */
  347.             typeFSS,            /* FSSpec descriptor.     */
  348.             ptr1,                /* Pointer to the data.     */
  349.             sizeof(FSSpec)        /* Size of the data.     */
  350.         );
  351.         HSetState((Handle)frHndl, hstate);
  352.         if (!err) {
  353.             opponentName[0] = 0;
  354.             userNameHndl = GetResource('STR ', -16096);
  355.             if (userNameHndl)
  356.                 pcpy(opponentName, (StringPtr)(*userNameHndl));
  357.             err = AEPutPtr(            /* ADD USER NAME TO LIST. */
  358.                 &sendGameList,        /* List to add to.             */
  359.                 4L,                    /* Make this element #4.     */
  360.                 typePascal,            /* Pascal string descriptor. */
  361.                 (Ptr)opponentName,    /* Pointer to the data.         */
  362.                 opponentName[0] + 1    /* Size of the data.         */
  363.             );
  364.             if (!err) {
  365.                 GetFullPathAndAppName(reconnectPath, reconnectApp);
  366.                 err = AEPutPtr(                /* ADD USER NAME TO LIST. */
  367.                     &sendGameList,            /* List to add to.             */
  368.                     5L,                        /* Make this element #5.     */
  369.                     typePascal2,            /* Pascal string descriptor. */
  370.                     (Ptr)reconnectPath,        /* Pointer to the data.         */
  371.                     reconnectPath[0] + 1    /* Size of the data.         */
  372.                 );
  373.                 if (!err) {
  374.                     err = AEPutPtr(                /* ADD USER NAME TO LIST. */
  375.                         &sendGameList,            /* List to add to.             */
  376.                         6L,                        /* Make this element #5.     */
  377.                         typePascal3,            /* Pascal string descriptor. */
  378.                         (Ptr)reconnectApp,        /* Pointer to the data.         */
  379.                         reconnectApp[0] + 1        /* Size of the data.         */
  380.                     );
  381.                 }
  382.             }
  383.         }
  384.     }
  385.  
  386.     if (!err) {        /* If we could add the game moves to the list... */
  387.         err = AECreateAppleEvent(            /* CREATE EMPTY APPLEEVENT.     */
  388.             kCustomEventClass,                /* Event class.                 */
  389.             kibitzAESendGame,                /* Event ID.                 */
  390.             &locOfOpponent,                    /* Address of receiving app. */
  391.             kAutoGenerateReturnID,            /* This value causes the     */
  392.                                             /* AppleEvent manager to     */
  393.                                             /* assign a return ID that     */
  394.                                             /* is unique to the session. */
  395.             kAnyTransactionID,                /* Ignore transaction ID.     */
  396.             &theAevt                        /* Location of event.         */
  397.         );
  398.     }
  399.  
  400.     if (!err) {        /* If we have an empty AppleEvent... */
  401.         err = AEPutParamDesc(    /* PUT THE LIST INTO THE APPLEEVENT.  */
  402.             &theAevt,            /* AppleEvent to add list to.          */
  403.             keyDirectObject,    /* This is our direct (only) object.  */
  404.             &sendGameList        /* The list to add to the AppleEvent. */
  405.         );
  406.     }
  407.  
  408.     replyType = (!twoPlayer) ? kAEQueueReply : kAENoReply;
  409.         /* Queue a reply only for a new game. */
  410.  
  411.     if (!err) {        /* If we have an AppleEvent ready to send... */
  412.         err = AESend(        /* SEND APPLEEVENT.                */
  413.             &theAevt,        /* Our Apple Event to send.        */
  414.             &reply,            /* We may have a reply.            */
  415.             replyType,        /* Type of reply.                */
  416.             PRIORITY,        /* App. send priority.            */
  417.             0,                /* We aren't waiting.            */
  418.             nil,            /* We aren't waiting.            */
  419.             nil                /* EventFilterProcPtr.            */
  420.         );
  421.     }
  422.     if (replyType == kAEQueueReply)
  423.         if (locOfOpponent.descriptorType == typeProcessSerialNumber)
  424.             err = ReceiveGameReply(&reply, &reply);
  425.                 /* If we want a queue reply, and if we are sending to ourselves,
  426.                 ** then we already have the reply.  Since we are sending to
  427.                 ** ourselves, we don't have to wait for an event.  Stuff happens
  428.                 ** right away.  We're (probably) happy. */
  429.  
  430.     AEDisposeDesc(&sendGameList);
  431.     AEDisposeDesc(&theAevt);
  432.     AEDisposeDesc(&reply);
  433.         /* Dispose of the descriptors, created or not.
  434.         ** If not created, no harm done by calling. */
  435.  
  436.     if (err) {
  437.         AEDisposeDesc(&locOfOpponent);
  438.             /* If we didn't connect, get rid of the target descriptor. */
  439.  
  440.         (*frHndl)->doc.gameID_0 = 0;
  441.         (*frHndl)->doc.gameID_1 = 0;
  442.             /* Mark this window so that it will never be found if we somehow
  443.             ** do get an answer from the receiver, even after failure. */
  444.     }
  445.  
  446.     return(err);
  447. }
  448.  
  449.  
  450.  
  451. /*****************************************************************************/
  452.  
  453.  
  454.  
  455. /* This code is executed only after an game is initially sent and we receive
  456. ** an AEAnswer event.  The "answer" is acknowledgment that the opponent
  457. ** received the game and that the opponent is set up for a two-player game.
  458. ** In the reply, we receive the opponent's game ID, which is used to match
  459. ** up which game receives the AppleEvents. */
  460.  
  461. pascal OSErr    ReceiveGameReply(AppleEvent *message, AppleEvent *reply)
  462. {
  463. #ifndef __MWERKS__
  464. #pragma unused (reply)
  465. #endif
  466.  
  467.     OSErr            err, replyErr;
  468.     DescType        actualType;
  469.     long            gameID[2], actualSize, mssgSize;
  470.     char            hstate;
  471.     WindowPtr        window;
  472.     FileRecHndl        frHndl;
  473.     Handle            mssgData;
  474.     Str32            opponentName, zone, machine, application;
  475.     Str255            reconnectPath;
  476.     Str32            reconnectApp;
  477.     AEAddressDesc    locOfOpponent;
  478.     short            txFont, txSize;
  479.     Style            txFace;
  480.     WindowPtr        oldPort, curPort;
  481.     Handle            finf;
  482.  
  483.     err = AEGetParamPtr(        /* CHECK FOR A RECEIVER ERROR... */
  484.         message,                /* The AppleEvent.              */
  485.         keyReplyErr,            /* AEKeyword                 */
  486.         typeShortInteger,        /* Desired type.             */
  487.         &actualType,            /* Type code.                 */
  488.         (Ptr)&replyErr,            /* Pointer to area for data. */ 
  489.         sizeof(short),            /* Size of data area.         */
  490.         &actualSize                /* Returned size of data.     */
  491.     );
  492.     if (!err) err = replyErr;
  493.  
  494.     if (!err) {
  495.         err = AEGetParamPtr(    /* GET RECEIVER GAME ID. */
  496.             message,            /* The AppleEvent.              */
  497.             keyGameID,            /* AEKeyword                 */
  498.             typeDoubleLong,        /* Desired type.             */
  499.             &actualType,        /* Type code.                 */
  500.             (Ptr)&gameID[0],    /* Pointer to area for data. */ 
  501.             2 * sizeof(long),    /* Size of data area.         */
  502.             &actualSize            /* Returned size of data.     */
  503.         );
  504.     }
  505.  
  506.     if (!err) {        /* If we got the receiver game ID... */
  507.  
  508.         window = GetGameWindow(gameID[1], gameID[1]);
  509.             /* The ID's are still both ours, since this is where we
  510.             ** get the receiver's ID returned.  gameID[0] holds the
  511.             ** receiver's ID, and gameID[1] holds ours. */
  512.  
  513.         if (window) {
  514.             frHndl = (FileRecHndl)GetWRefCon(window);
  515.             if (!(*frHndl)->doc.twoPlayer) {
  516.                 err = AEGetParamPtr(
  517.                     message,            /* The AppleEvent.              */
  518.                     keyPascalReply,        /* AEKeyword                 */
  519.                     typePascal,            /* Desired type.             */
  520.                     &actualType,        /* Type code.                 */
  521.                     (Ptr)opponentName,    /* Pointer to area for data. */ 
  522.                     sizeof(Str32),        /* Size of data area.         */
  523.                     &actualSize            /* Returned size of data.     */
  524.                 );
  525.  
  526.                 (*frHndl)->doc.opponentName[0] = 0;
  527.                 if (!err) {
  528.                     (*frHndl)->doc.gameID_1 = gameID[0];
  529.                     pcpy(&(*frHndl)->doc.opponentName[0], opponentName);
  530.                     SetOpponentType(frHndl, kTwoPlayer);
  531.                     locOfOpponent = (*frHndl)->doc.locOfOpponent;
  532.                     zone[0] = machine[0] = 0;
  533.                     GetTargetInfo(locOfOpponent, zone, machine, application);
  534.                     pcpy(&(*frHndl)->doc.opponentZone[0], zone);
  535.                     pcpy(&(*frHndl)->doc.opponentMachine[0], machine);
  536.  
  537.                     err = AEGetParamPtr(
  538.                         message,            /* The AppleEvent.              */
  539.                         keyPascal2Reply,    /* AEKeyword                 */
  540.                         typePascal2,        /* Desired type.             */
  541.                         &actualType,        /* Type code.                 */
  542.                         (Ptr)reconnectPath,    /* Pointer to area for data. */ 
  543.                         sizeof(Str255),        /* Size of data area.         */
  544.                         &actualSize            /* Returned size of data.     */
  545.                     );
  546.                     (*frHndl)->doc.reconnectPath[0] = 0;
  547.                     if (!err) pcpy(&(*frHndl)->doc.reconnectPath[0], reconnectPath);
  548.  
  549.                     err = AEGetParamPtr(
  550.                         message,            /* The AppleEvent.              */
  551.                         keyPascal3Reply,    /* AEKeyword                 */
  552.                         typePascal3,        /* Desired type.             */
  553.                         &actualType,        /* Type code.                 */
  554.                         (Ptr)reconnectApp,    /* Pointer to area for data. */ 
  555.                         sizeof(Str32),        /* Size of data area.         */
  556.                         &actualSize            /* Returned size of data.     */
  557.                     );
  558.                     (*frHndl)->doc.reconnectApp[0] = 0;
  559.                     if (!err) pcpy(&(*frHndl)->doc.reconnectApp[0], reconnectApp);
  560.  
  561.                     if (!err) {
  562.                         err = AEGetParamPtr(
  563.                             message,                /* The AppleEvent.              */
  564.                             keyTextMessage,            /* AEKeyword                 */
  565.                             typeMssg,                /* Desired type.             */
  566.                             &actualType,            /* Type code.                 */
  567.                             nil,                    /* Pointer to area for data. */ 
  568.                             0,                        /* Size of data area.         */
  569.                             &mssgSize                /* Returned size of data.     */
  570.                         );
  571.                     }
  572.                     mssgData = nil;
  573.                     if (!err) {        /* Get the data... */
  574.                         mssgData = NewHandle(mssgSize);
  575.                         if (mssgData) {
  576.                             hstate = LockHandleHigh(mssgData);
  577.                             err = AEGetParamPtr(
  578.                                 message,                /* The AppleEvent.              */
  579.                                 keyTextMessage,            /* AEKeyword                 */
  580.                                 typeMssg,                /* Desired type.             */
  581.                                 &actualType,            /* Type code.                 */
  582.                                 *mssgData,                /* Pointer to area for data. */ 
  583.                                 mssgSize,                /* Size of data area.         */
  584.                                 &actualSize                /* Returned size of data.     */
  585.                             );
  586.                         }
  587.                         else err = memFullErr;
  588.                     }
  589.                     if (!err) {
  590.                         oldPort = SetFilePort(frHndl);
  591.                         GetPort(&curPort);
  592.                         txFont = curPort->txFont;
  593.                         txSize = curPort->txSize;
  594.                         txFace = curPort->txFace;
  595.                         finf = GetResource('finf', 128);
  596.                         TextFont((*(short **)finf)[1]);
  597.                         TextSize((*(short **)finf)[3]);
  598.                         TextFace(normal);
  599.                         mssgData = CTESwapText((*frHndl)->doc.message[kMessageIn],
  600.                                                 mssgData, nil, true);
  601.                         TextFont(txFont);
  602.                         TextSize(txSize);
  603.                         TextFace(txFace);
  604.                         SetPort(oldPort);
  605.                     }
  606.                     if (mssgData) DisposeHandle(mssgData);
  607.  
  608.                     if (err == errAEDescNotFound) err = noErr;
  609.                 }
  610.                 if (err) (*frHndl)->doc.gameID_0 = (*frHndl)->doc.gameID_1 = 0;
  611.                 else GetDateTime(&((*frHndl)->doc.timeLastReceive));
  612.             }
  613.         }
  614.     }
  615.  
  616.     return(err);
  617. }
  618.  
  619.  
  620.  
  621. /*****************************************************************************/
  622.  
  623.  
  624.  
  625. /* ReceiveGame
  626. **
  627. ** This routine receives a board from an opponent.  It receives it for various
  628. ** purposes.  These are:
  629. **   1) Establishing a new game.
  630. **   2) Receiving a move.
  631. **   3) Receiving a new board position, due to scrolling.
  632. **
  633. ** Establishing a new game is determined by the fact that the value twoPlayer
  634. ** is false.  If it is a previously established game, then this field is true.
  635. **
  636. ** If it is a previously established game, then whether or not it is a new move
  637. ** is determined by field "sendReason".  If sendReason != kIsMove, then it is some
  638. ** other change, such as scrolling or resyncing by of the sender.
  639. ** These other cases should not cause a win/loss/tie dialog to appear.
  640. **
  641. ** If it is a regular move, (sendReason == kIsMove), then the win/loss/draw dialogs
  642. ** should be displayed, if the game is indeed over after the move. */
  643.  
  644. pascal OSErr    ReceiveGame(AppleEvent *message, AppleEvent *reply, long refcon)
  645. {
  646. #ifndef __MWERKS__
  647. #pragma unused (refcon)
  648. #endif
  649.  
  650.     OSErr            err;
  651.     FileRecHndl        frHndl, newFrHndl, oldFrHndl, mssgFrHndl;
  652.     FileRecPtr        frPtr;
  653.     AEDescList        receiveGameList;
  654.     char            hstate;
  655.     Ptr                ptr1, ptr2;
  656.     long            size, gameID[2];
  657.     Boolean            twoPlayer;
  658.     AEAddressDesc    senderTarget;
  659.     AEKeyword        ignoredKeyWord;
  660.     DescType        ignoredType;
  661.     Size            ignoredSize;
  662.     GameListHndl    gameMoves;
  663.     WindowPtr        oldPort, window, fwindow, behindWindow;
  664.     WindowPeek        wpeek;
  665.     FSSpec            myFSS;
  666.     Str32            opponentName, zone, machine, application;
  667.     Str255            reconnectPath;
  668.     Str32            reconnectApp;
  669.     Handle            userNameHndl, hText;
  670.     short            i, drawBtnState, sendReason, myColor, invertBoard, fromSq, toSq;
  671.     GameListHndl    oldGame, newGame;
  672.     GameElement        *optr, *nptr;
  673.     short            oldGameIndex, newGameIndex, oldNumMoves, newNumMoves, identical;
  674.     TEHandle        te;
  675.  
  676.     err = noErr;
  677.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  678.         reply,                    /* The AppleEvent.              */
  679.         keyReplyErr,            /* AEKeyword                 */
  680.         typeShortInteger,        /* Desired type.             */
  681.         (Ptr)&err,                /* Pointer to area for data. */ 
  682.         sizeof(short)            /* Size of data area.         */
  683.     );
  684.  
  685.     receiveGameList.dataHandle = nil;
  686.         /* Make sure disposing of the descriptors is okay in all cases.
  687.         ** This will not be necessary after 7.0b3, since the calls that
  688.         ** attempt to create the descriptors will nil automatically
  689.         ** upon failure. */
  690.  
  691.     IncNewFileNum(false);
  692.     err = AppNewDocument(&newFrHndl, ksOrigName);
  693.     IncNewFileNum(true);
  694.  
  695.     if (err) return(err);
  696.  
  697.     /* We have a new document... */
  698.     err = AEGetParamDesc(    /* GET THE APPLEEVENT LIST.  */
  699.         message,            /* AppleEvent to holding list.          */
  700.         keyDirectObject,    /* This is our direct (only) object.  */
  701.         typeWildCard,        /* Desired type is game list.          */
  702.         &receiveGameList    /* The list to add to the AppleEvent. */
  703.     );
  704.  
  705.     if (!err) {        /* If we got the list descriptor... */
  706.         hstate = LockHandleHigh((Handle)newFrHndl);
  707.         ptr1   = (Ptr)&((*newFrHndl)->doc);
  708.         ptr2   = (Ptr)&((*newFrHndl)->doc.endSendInfo);
  709.         size   = (long)ptr2 - (long)ptr1;
  710.         err = AEGetNthPtr(        /* GET BOARD INFO FROM THE LIST.     */
  711.             &receiveGameList,    /* List to get from.                 */
  712.             1L,                    /* Get first item in list.             */
  713.             typeTheBoard,        /* First item is the board.             */
  714.             &ignoredKeyWord,    /* Returned keyword -- we know.         */
  715.             &ignoredType,        /* Returned type -- we know.         */
  716.             ptr1,                /* Where to put the board info.         */
  717.             size,                /* Size of the board.                 */
  718.             &ignoredSize        /* Actual size -- we know.             */
  719.         );
  720.         HSetState((Handle)newFrHndl, hstate);
  721.     }
  722.  
  723.     if (!err) {        /* If we got the board... */
  724.         gameMoves = (*newFrHndl)->doc.gameMoves;
  725.         size      = (*newFrHndl)->doc.numGameMoves * sizeof(GameElement);
  726.         SetHandleSize((Handle)gameMoves, size);
  727.         err = MemError();
  728.         if (!err) {
  729.             hstate = LockHandleHigh((Handle)gameMoves);
  730.             err = AEGetNthPtr(        /* GET GAME MOVES FROM THE LIST.     */
  731.                 &receiveGameList,    /* List to get from.                 */
  732.                 2L,                    /* Get second item in list.             */
  733.                 typeGameMoves,        /* Second item is the game moves.     */
  734.                 &ignoredKeyWord,    /* Returned keyword -- we know.         */
  735.                 &ignoredType,        /* Returned type -- we know.         */
  736.                 (Ptr)(*gameMoves),    /* Where to put the moves.             */
  737.                 size,                /* Size of the board.                 */
  738.                 &ignoredSize        /* Actual size -- we know.             */
  739.             );
  740.             HSetState((Handle)gameMoves, hstate);
  741.         }
  742.     }
  743.  
  744.  
  745.  
  746.     if (!err) {
  747.  
  748.         /* We now have the board and game moves, in newFrHndl.  This is either a
  749.         ** new opponent, or an update from an old opponent.  Let's see... */
  750.  
  751.         twoPlayer = (*newFrHndl)->doc.twoPlayer;
  752.         (*newFrHndl)->doc.twoPlayer = false;
  753.             /* See if this is an already existing opponent, or a new one. */
  754.     
  755.         if (!twoPlayer) {        /* If new game... */
  756.             err = AEGetAttributeDesc(    /* GET ADDRESS OF NEW OPPONENT.     */
  757.                 message,                /* Get address of sender from message.         */
  758.                 keyAddressAttr,            /* We want an address.                         */
  759.                 typeWildCard,            /* We want the address of the sender.         */
  760.                 &senderTarget            /* Address of sender.                         */
  761.             );
  762.             if (!err) {
  763.                 (*newFrHndl)->doc.twoPlayer     = true;
  764.                 (*newFrHndl)->doc.arrangeBoard  = false;
  765.                 (*newFrHndl)->doc.locOfOpponent = senderTarget;
  766.                 err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  767.                     &receiveGameList,    /* List to get from.            */
  768.                     3L,                    /* Get second item in list.        */
  769.                     typeFSS,            /* Third item is the FSSpec.    */
  770.                     &ignoredKeyWord,    /* Returned keyword -- we know. */
  771.                     &ignoredType,        /* Returned type -- we know.    */
  772.                     (Ptr)&myFSS,        /* Where to put the FSSpec.        */
  773.                     sizeof(FSSpec),        /* Size of the data.            */
  774.                     &ignoredSize        /* Actual size -- we know.        */
  775.                 );
  776.                 if (!err)
  777.                     pcpy((*newFrHndl)->fileState.fss.name, myFSS.name);
  778.             }
  779.             if (!err) {
  780.                 err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  781.                     &receiveGameList,    /* List to get from.                */
  782.                     4L,                    /* Get second item in list.            */
  783.                     typePascal,            /* Third item is the opponent name.    */
  784.                     &ignoredKeyWord,    /* Returned keyword -- we know.     */
  785.                     &ignoredType,        /* Returned type -- we know.        */
  786.                     (Ptr)opponentName,    /* Where to put the opponent name.    */
  787.                     sizeof(Str32),        /* Size of the data.                */
  788.                     &ignoredSize        /* Actual size.                        */
  789.                 );
  790.                 (*newFrHndl)->doc.opponentName[0] = 0;
  791.                 if (!err) {
  792.                     pcpy((*newFrHndl)->doc.opponentName, opponentName);
  793.                     zone[0] = machine[0] = 0;
  794.                     GetTargetInfo(senderTarget, zone, machine, application);
  795.                     pcpy((*newFrHndl)->doc.opponentZone, zone);
  796.                     pcpy((*newFrHndl)->doc.opponentMachine, machine);
  797.                     GetDateTime(&((*newFrHndl)->doc.timeLastReceive));
  798.                 }
  799.                 if (!err) {
  800.                     err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  801.                         &receiveGameList,    /* List to get from.                */
  802.                         5L,                    /* Get second item in list.            */
  803.                         typePascal2,        /* Third item is the opponent name.    */
  804.                         &ignoredKeyWord,    /* Returned keyword -- we know.     */
  805.                         &ignoredType,        /* Returned type -- we know.        */
  806.                         (Ptr)reconnectPath,    /* Where to put the opponent name.    */
  807.                         sizeof(Str255),        /* Size of the data.                */
  808.                         &ignoredSize        /* Actual size.                        */
  809.                     );
  810.                     (*newFrHndl)->doc.reconnectPath[0] = 0;
  811.                     if (!err) pcpy((*newFrHndl)->doc.reconnectPath, reconnectPath);
  812.                 }
  813.                 if (!err) {
  814.                     err = AEGetNthPtr(        /* GET FSSpec (FOR GAME NAME) FROM LIST. */
  815.                         &receiveGameList,    /* List to get from.                */
  816.                         6L,                    /* Get second item in list.            */
  817.                         typePascal3,        /* Third item is the opponent name.    */
  818.                         &ignoredKeyWord,    /* Returned keyword -- we know.     */
  819.                         &ignoredType,        /* Returned type -- we know.        */
  820.                         (Ptr)reconnectApp,    /* Where to put the opponent name.    */
  821.                         sizeof(Str32),        /* Size of the data.                */
  822.                         &ignoredSize        /* Actual size.                        */
  823.                     );
  824.                     (*newFrHndl)->doc.reconnectApp[0] = 0;
  825.                     if (!err) pcpy((*newFrHndl)->doc.reconnectApp, reconnectApp);
  826.                 }
  827.             }
  828.         }
  829.     }
  830.  
  831.     if (!err) {        /* If we got the opponent address... */
  832.  
  833.         if (!twoPlayer) {        /* It is a new game... */
  834.  
  835.             (*newFrHndl)->doc.timerRefTick = TickCount();
  836.                 /* Set the timer reference early as possible.
  837.                 ** This syncs the two clocks as much as possible. */
  838.  
  839.                 /* For a new opponent, then we need to ID the receiver side
  840.                 ** of the sender/receiver ID pair.  We also need to send
  841.                 ** back the receiver portion of the ID pair for the sender. */
  842.  
  843.             (*newFrHndl)->doc.gameID_0 = gameID[0] = (TickCount() | 0x01);
  844.             (*newFrHndl)->doc.myColor     ^= 1;
  845.             (*newFrHndl)->doc.invertBoard ^= 1;
  846.                 /* We are the opposite color/side as the opponent. */
  847.  
  848.             if ((*newFrHndl)->doc.version != kVersion) err = errAEWrongDataType;
  849.                 /* Incompatible file format. */
  850.  
  851.             if (!err) {
  852.                 gameID[1] = (*newFrHndl)->doc.gameID_1;
  853.                 err = AEPutParamPtr(    /* RETURN RECEIVER GAME ID.     */
  854.                     reply,                /* The AppleEvent.              */
  855.                     keyGameID,            /* AEKeyword                 */
  856.                     typeDoubleLong,        /* Type code.                 */
  857.                     (Ptr)&gameID[0],    /* Pointer to area for data. */ 
  858.                     2 * sizeof(long)    /* Size of data area.         */
  859.                 );
  860.             }
  861.  
  862.             if (!err) {
  863.                 opponentName[0] = 0;
  864.                 userNameHndl = GetResource('STR ', -16096);
  865.                 if (userNameHndl)
  866.                     pcpy(opponentName, (StringPtr)(*userNameHndl));
  867.                 err = AEPutParamPtr(    /* RETURN RECEIVER GAME ID.     */
  868.                     reply,                /* The AppleEvent.              */
  869.                     keyPascalReply,        /* AEKeyword                 */
  870.                     typePascal,            /* Type code.                 */
  871.                     (Ptr)opponentName,    /* Pointer to area for data. */ 
  872.                     opponentName[0] + 1    /* Size of data area.         */
  873.                 );
  874.             }
  875.  
  876.             if (!err) {
  877.                 GetFullPathAndAppName(reconnectPath, reconnectApp);
  878.                 err = AEPutParamPtr(        /* RETURN RECEIVER GAME ID.     */
  879.                     reply,                    /* The AppleEvent.              */
  880.                     keyPascal2Reply,        /* AEKeyword                 */
  881.                     typePascal2,            /* Type code.                 */
  882.                     (Ptr)reconnectPath,        /* Pointer to area for data. */ 
  883.                     reconnectPath[0] + 1    /* Size of data area.         */
  884.                 );
  885.                 if (!err) {
  886.                     err = AEPutParamPtr(        /* RETURN RECEIVER GAME ID.     */
  887.                         reply,                    /* The AppleEvent.              */
  888.                         keyPascal3Reply,        /* AEKeyword                 */
  889.                         typePascal3,            /* Type code.                 */
  890.                         (Ptr)reconnectApp,        /* Pointer to area for data. */ 
  891.                         reconnectApp[0] + 1    /* Size of data area.         */
  892.                     );
  893.                 }
  894.             }
  895.  
  896.             if (!err) {
  897.                 if (IsAppWindow(fwindow = FrontWindow())) {
  898.                     frPtr = *(frHndl = (FileRecHndl)GetWRefCon(fwindow));
  899.                     if (
  900.                         (frPtr->doc.myColor != kMessageDoc) &&
  901.                         (!(frPtr->doc.arrangeBoard)) &&
  902.                         (!(frPtr->doc.twoPlayer)) &&
  903.                         (!(frPtr->doc.numGameMoves)) &&
  904.                         (!(frPtr->doc.gameID_0)) &&
  905.                         (!(frPtr->doc.timeLastReceive))
  906.                     ) {
  907.                         AppDisposeDocument(frHndl);
  908.                         DisposeAnyWindow(fwindow);
  909.                     }
  910.                 }
  911.                 behindWindow = (WindowPtr)-1;
  912.                 for (wpeek = LMGetWindowList(); wpeek; wpeek = wpeek->nextWindow) {
  913.                     if (IsAppWindow((WindowPtr)wpeek)) {
  914.                         frPtr = *(FileRecHndl)GetWRefCon((WindowPtr)wpeek);
  915.                         if (
  916.                             (frPtr->doc.myColor != kMessageDoc) &&
  917.                             (!(frPtr->doc.arrangeBoard)) &&
  918.                             (!(frPtr->doc.twoPlayer)) &&
  919.                             (!(frPtr->doc.numGameMoves))
  920.                         ) break;
  921.                         behindWindow = (WindowPtr)wpeek;
  922.                     }
  923.                 }
  924.                 err = AppNewWindow(newFrHndl, nil, behindWindow);
  925.             }
  926.  
  927.                 /* If everything worked for new opponent, give the new document a window. */
  928.  
  929.             if (!err) {
  930.                 AdjustGameSlider(newFrHndl);
  931.  
  932.                 DrawButtonTitle(newFrHndl, kTwoPlayer);
  933.                     /* Convert the draw button to two player. */
  934.  
  935.                 (*newFrHndl)->doc.gotUpdateTick = TickCount();
  936.                     /* Record when we got the event. */
  937.  
  938.                 fwindow = FrontWindow();
  939.                 mssgFrHndl = (FileRecHndl)GetWRefCon((WindowPtr)fwindow);
  940.                 if ((*mssgFrHndl)->doc.myColor == kMessageDoc) {
  941.                     te     = (*mssgFrHndl)->doc.message[kMessageOut];
  942.                     hText  = (*te)->hText;
  943.                     hstate = LockHandleHigh(hText);
  944.                     size   = (*te)->teLength;
  945.                     err = AEPutParamPtr(
  946.                         reply,
  947.                         keyTextMessage,
  948.                         typeMssg,
  949.                         *hText,
  950.                         size
  951.                     );
  952.                     HSetState(hText, hstate);
  953.                 }
  954.             }
  955.         }
  956.         else {        /* It is an update to an existing game. */
  957.  
  958.             window = GetGameWindow(
  959.                 (*newFrHndl)->doc.gameID_1, (*newFrHndl)->doc.gameID_0);
  960.                     /* Get the window for the existing game. */
  961.  
  962.             if (window) {        /* This game still exists... */
  963.  
  964.                 oldFrHndl = (FileRecHndl)GetWRefCon(window);
  965.                 UpdateTime(oldFrHndl, false);
  966.  
  967.                 if ((*oldFrHndl)->doc.resync < (sendReason = (*newFrHndl)->doc.sendReason))
  968.                     (*oldFrHndl)->doc.resync = sendReason;
  969.                         /* Bump up resync, if needed. */
  970.  
  971.                 if (sendReason == kScrolling) {
  972.                     if (
  973.                         ((*oldFrHndl)->doc.resync == kResync) || 
  974.                         ((*oldFrHndl)->doc.gotUpdateTick + 30 > TickCount())
  975.                     ) {
  976.                         window = nil;
  977.                         AppDisposeDocument(newFrHndl);
  978.                                 /* Temporary document now gone. */
  979.                     }    /* If it has been less than 1/2 second since the last
  980.                         ** scroll update received, or if the user has finished
  981.                         ** scrolling, then we can ignore this scroll event.
  982.                         ** This keeps us from getting behind in the processing
  983.                         ** of scroll events. */
  984.                 }
  985.             }
  986.             else
  987.                 err = memFullErr;
  988.                     /* Can't find the old window, so cause some kind of error. */
  989.  
  990.             if (window) {        /* This game still exists... */
  991.  
  992.                 if (sendReason != kIsMove) {
  993.                     for (i = 0; i < 2; ++i)
  994.                         (*newFrHndl)->doc.timeLeft[i] = (*oldFrHndl)->doc.timeLeft[i];
  995.                             /* Keep our clock values if opponent is scrolling or resyncing. */
  996.                 }
  997.  
  998.                 frPtr        = *oldFrHndl;
  999.                 oldGameIndex = frPtr->doc.gameIndex;
  1000.                 oldNumMoves  = frPtr->doc.numGameMoves;
  1001.                 oldGame      = frPtr->doc.gameMoves;
  1002.                 frPtr        = *newFrHndl;
  1003.                 newGameIndex = frPtr->doc.gameIndex;
  1004.                 newNumMoves  = frPtr->doc.numGameMoves;
  1005.                 newGame      = frPtr->doc.gameMoves;
  1006.                 if ((oldGameIndex == newGameIndex) && (oldNumMoves == newNumMoves)) {
  1007.                     optr = &(**oldGame)[0];
  1008.                     nptr = &(**newGame)[0];
  1009.                     identical = true;
  1010.                     for (i = 0; i < oldNumMoves; ++i, ++optr, ++nptr) {
  1011.                         if (
  1012.                             (optr->moveFrom          != nptr->moveFrom) ||
  1013.                             (optr->moveTo            != nptr->moveTo) ||
  1014.                             (optr->pieceCaptured     != nptr->pieceCaptured) ||
  1015.                             (optr->pieceCapturedFrom != nptr->pieceCapturedFrom) ||
  1016.                             (optr->promoteTo         != nptr->promoteTo)
  1017.                         ) {
  1018.                             identical = false;
  1019.                             break;
  1020.                         }
  1021.                     }
  1022.                 }
  1023.                 else identical = false;
  1024.  
  1025.                 myColor     = (*oldFrHndl)->doc.myColor;
  1026.                 invertBoard = (*oldFrHndl)->doc.invertBoard;
  1027.                     /* These need to be saved, so they are in that section,
  1028.                     ** but they are private info, so cache them. */
  1029.  
  1030.                 ptr1 = (Ptr)&((*newFrHndl)->doc);
  1031.                 ptr2 = (Ptr)&((*newFrHndl)->doc.endFileInfo1);
  1032.                 size = (long)ptr2 - (long)ptr1;
  1033.                 ptr2 = (Ptr)&((*oldFrHndl)->doc);
  1034.                 BlockMove(ptr1, ptr2, size);
  1035.  
  1036.                 (*oldFrHndl)->doc.myColor     = myColor;
  1037.                 (*oldFrHndl)->doc.invertBoard = invertBoard;
  1038.                     /* Restore our private cached values. */
  1039.  
  1040.                 (*newFrHndl)->doc.gameMoves = (*oldFrHndl)->doc.gameMoves;
  1041.                 (*oldFrHndl)->doc.gameMoves = gameMoves;
  1042.                     /* Swap the game move handles.  The existing document
  1043.                     ** is now updated completely.  We can dispose of the
  1044.                     ** temporary new one.  (gameMoves is set above for
  1045.                     ** the handle for the new document.) */
  1046.  
  1047.                 i = (*newFrHndl)->doc.drawBtnState;
  1048.                 drawBtnState = kTwoPlayer;
  1049.                 if (i & 0x02) drawBtnState |= 0x04;
  1050.                 if (i & 0x04) drawBtnState |= 0x02;
  1051.  
  1052.                 AppDisposeDocument(newFrHndl);
  1053.                     /* Temporary document now gone. */
  1054.  
  1055.                 GetPort(&oldPort);
  1056.                 SetPort(window);
  1057.  
  1058.                 if (!identical) {        /* There was a change, so show it. */
  1059.                     if (sendReason == kIsMove) {
  1060.                     if (GetControlValue((*oldFrHndl)->doc.beepOnMove)) SysBeep(1);
  1061.                         if (GameStatus(oldFrHndl) <= kDrawByRep) {
  1062.                             MakeMove(oldFrHndl, -1, 0, 0);
  1063.                             oldGame      = (*oldFrHndl)->doc.gameMoves;
  1064.                             oldGameIndex = (*oldFrHndl)->doc.gameIndex;
  1065.                             fromSq = (**oldGame)[oldGameIndex].moveFrom;
  1066.                             toSq   = (**oldGame)[oldGameIndex].moveTo;
  1067.                             SlideThePiece(oldFrHndl, fromSq, toSq);
  1068.                             MakeMove(oldFrHndl, 1, 0, 0);
  1069.                             SayTheMove(oldFrHndl);
  1070.                         }
  1071.                     }
  1072.                     ImageDocument(oldFrHndl, true);
  1073.                     AdjustGameSlider(oldFrHndl);
  1074.                 }
  1075.  
  1076.                 DrawButtonTitle(oldFrHndl, drawBtnState);
  1077.                 UpdateGameStatus(oldFrHndl);
  1078.                     /* Update the text of the draw button. */
  1079.  
  1080.                 DrawTime(oldFrHndl);
  1081.  
  1082.                 (*oldFrHndl)->doc.gotUpdateTick = TickCount();
  1083.                     /* Record when we got the event. */
  1084.  
  1085.                 if (sendReason == kIsMove) {
  1086.                     (*oldFrHndl)->fileState.docDirty = true;
  1087.                     AlertIfGameOver(oldFrHndl);
  1088.                         /* For non-moves, we don't want to beep or
  1089.                         ** show a game-over dialog. */
  1090.                 }
  1091.                 SetPort(oldPort);
  1092.             }
  1093.         }
  1094.     }
  1095.  
  1096.     if (err) AppDisposeDocument(newFrHndl);
  1097.         /* This won't get done twice, even though there is an
  1098.         ** AppDisposeDocument(newFrHndl) earlier.  The earlier
  1099.         ** one only happens if no error occured, and this one
  1100.         ** only happens on an error condition. */
  1101.  
  1102.     AEDisposeDesc(&receiveGameList);
  1103.         /* Dispose of the descriptors, created or not.
  1104.         ** If not created, no harm done by calling. */
  1105.  
  1106.     if (!err) NotifyUser();
  1107.     return(err);
  1108. }
  1109.  
  1110.  
  1111.  
  1112. /*****************************************************************************/
  1113.  
  1114.  
  1115.  
  1116. /* Send one of various messages to the opponent.  There is a common set of
  1117. ** data that needs to be sent so that the opponent can determine which game
  1118. ** the message should be applied.  Then there is message-specific data that
  1119. ** is handled case by case.  Once the message is completed, it is sent off
  1120. ** to the opponent.  The additional task of updating the state of our game
  1121. ** is also handled here.  For example:  When text is sent, the text on our
  1122. ** machine is selected to make it easier to replace the old text with new
  1123. ** text.  Any typing by the user will replace the selected text (all the text)
  1124. ** with the newly typed text.  */
  1125.  
  1126. Boolean    SendMssg(FileRecHndl frHndl, short messageType)
  1127. {
  1128.     AEAddressDesc    locOfOpponent;
  1129.     OSErr            err;
  1130.     TEHandle        teIn, teOut;
  1131.     char            hstate;
  1132.     AppleEvent        theAevt, reply;
  1133.     Handle            hText, snd, intxt, outtxt;
  1134.     RgnHandle        oldClip, newClip;
  1135.     TextStyle        styl;
  1136.     long            size, gameID[2], time[2];
  1137.     short            i, inlen, outlen, overflow;
  1138.     Boolean            twoPlayer;
  1139.     WindowPtr        oldPort, curPort;
  1140.     Point            pt;
  1141.     short            txFont, txSize;
  1142.     Style            txFace;
  1143.     Handle            finf;
  1144.  
  1145.     oldPort = SetFilePort(frHndl);
  1146.     GetPort(&curPort);
  1147.  
  1148.     theAevt.dataHandle = reply.dataHandle = nil;
  1149.         /* Make sure disposing of the descriptors is okay in all cases.
  1150.         ** This will not be necessary after 7.0b3, since the calls that
  1151.         ** attempt to create the descriptors will nil automatically
  1152.         ** upon failure. */
  1153.  
  1154.     err = noErr;
  1155.  
  1156.     twoPlayer = (*frHndl)->doc.twoPlayer;
  1157.     if (twoPlayer) {
  1158.  
  1159.         locOfOpponent = (*frHndl)->doc.locOfOpponent;
  1160.  
  1161.         err = AECreateAppleEvent(        /* CREATE EMPTY APPLEEVENT.     */
  1162.             kCustomEventClass,            /* Event class.                 */
  1163.             kibitzAESendMssg,            /* Event ID.                 */
  1164.             &locOfOpponent,                /* Address of receiving app. */
  1165.             kAutoGenerateReturnID,        /* This value causes the     */
  1166.                                         /* AppleEvent manager to     */
  1167.                                         /* assign a return ID that     */
  1168.                                         /* is unique to the session. */
  1169.             kAnyTransactionID,            /* Ignore transaction ID.     */
  1170.             &theAevt                    /* Location of event.         */
  1171.         );
  1172.  
  1173.         if (!err) {            /* Say what the message is. */
  1174.             AEPutParamPtr(
  1175.                 &theAevt,
  1176.                 keyDirectObject,
  1177.                 typeShortInteger,
  1178.                 (Ptr)&messageType,
  1179.                 sizeof(short)
  1180.             );
  1181.         }
  1182.  
  1183.         if (!err) {            /* Say what window message is for. */
  1184.             gameID[0] = (*frHndl)->doc.gameID_0;
  1185.             gameID[1] = (*frHndl)->doc.gameID_1;
  1186.             AEPutParamPtr(
  1187.                 &theAevt,
  1188.                 keyGameID,
  1189.                 typeDoubleLong,
  1190.                 (Ptr)&gameID[0],
  1191.                 2 * sizeof(long)
  1192.             );
  1193.         }
  1194.     }
  1195.  
  1196.     /* The stuff that applies to all messages is now done.  Now specifically
  1197.     ** handle all the different message types. */
  1198.  
  1199.     if (!err) {
  1200.         switch (messageType) {
  1201.  
  1202.             case kAmWhiteMssg:
  1203.             case kAmBlackMssg:
  1204.                 (*frHndl)->doc.configColor       = messageType;
  1205.                 (*frHndl)->doc.configColorChange = true;
  1206.                 (*frHndl)->doc.resync            = kHandResync;
  1207.                     /* The AppleEvent already has all the data the opponent
  1208.                     ** needs.  Post that a color change is happening.  The
  1209.                     ** reason that it is posted, instead of immediately applied,
  1210.                     ** is that we want to make sure that the opponent isn't
  1211.                     ** doing a color change operation at the same time.  The
  1212.                     ** color change will only occur when we get a NULL event.
  1213.                     ** The NULL event indicates that the opponent isn't sending
  1214.                     ** any AppleEvents at that time.  Waiting for quiescence
  1215.                     ** helps prevent the state of the game from getting
  1216.                     ** confused.  Also, the creator of the game echos the
  1217.                     ** color change, just to make sure that both machines are
  1218.                     ** in the same state.  (The echo doesn't occur until
  1219.                     ** there are no other AppleEvents happening.  This helps
  1220.                     ** keep the number of AppleEvents down, as well.) */
  1221.                 break;
  1222.  
  1223.             case kDisconnectMssg:
  1224.                     /* All the information we need is already in the AppleEvent. */
  1225.                 break;
  1226.  
  1227.             case kTimeMssg:
  1228.                 for (i = 0; i < 2; ++i)
  1229.                     time[i] = (*frHndl)->doc.configTime[i] = (*frHndl)->doc.timeLeft[i];
  1230.                 if (twoPlayer) {
  1231.                     err = AEPutParamPtr(
  1232.                         &theAevt,
  1233.                         keyTime,
  1234.                         typeDoubleLong,
  1235.                         (Ptr)&time[0],
  1236.                         2 * sizeof(long)
  1237.                     );
  1238.                     if ((*frHndl)->doc.resync)
  1239.                         (*frHndl)->doc.configTimeChange = true;
  1240.                     else {
  1241.                         for (i = 0; i < 2; ++i)
  1242.                             (*frHndl)->doc.timeLeft[i] =
  1243.                                 (*frHndl)->doc.displayTime[i] =
  1244.                                     (*frHndl)->doc.configTime[i];
  1245.                         UpdateTime(frHndl, false);
  1246.                         DrawTime(frHndl);
  1247.                     }
  1248.                 }
  1249.                 break;
  1250.  
  1251.             case kTextMssg:
  1252.                 if (twoPlayer) {
  1253.                     teOut  = (*frHndl)->doc.message[kMessageOut];
  1254.                     hText  = (*teOut)->hText;
  1255.                     hstate = LockHandleHigh(hText);
  1256.                     size   = (*teOut)->teLength;
  1257.                     err = AEPutParamPtr(
  1258.                         &theAevt,
  1259.                         keyTextMessage,
  1260.                         typeMssg,
  1261.                         *hText,
  1262.                         size
  1263.                     );
  1264.                     HSetState(hText, hstate);
  1265.                 }
  1266.                 break;
  1267.  
  1268.             case kSoundMssg:
  1269.                 if (twoPlayer) {
  1270.                     snd = (*frHndl)->doc.sound;
  1271.                     if (snd) {
  1272.                         hstate = LockHandleHigh(snd);
  1273.                         size   = GetHandleSize(snd);
  1274.                         err = AEPutParamPtr(
  1275.                             &theAevt,
  1276.                             keySoundMessage,
  1277.                             typeMssg,
  1278.                             *snd,
  1279.                             size
  1280.                         );
  1281.                         HSetState(snd, hstate);
  1282.                     }
  1283.                 }
  1284.                 break;
  1285.         }
  1286.     }
  1287.  
  1288.     if (twoPlayer) {
  1289.         if (!err) {        /* If everything looks good... */
  1290.             err = AESend(                /* SEND APPLEEVENT.                 */
  1291.                 &theAevt,                /* Our Apple Event to send.         */
  1292.                 &reply,                    /* We may have a reply.             */
  1293.                 kAENoReply,                /* Don't wait for reply.         */
  1294.                 PRIORITY,                /* App. send priority.             */
  1295.                 0,                        /* We aren't waiting.             */
  1296.                 nil,                    /* We don't wait, so no idleProc */
  1297.                 nil                        /* EventFilterProcPtr.             */
  1298.             );
  1299.         }
  1300.         if (!err) {
  1301.             switch (messageType) {
  1302.                 case kTextMssg:
  1303.  
  1304.                     finf = GetResource('finf', 128);
  1305.                     styl.tsFont = (*(short **)finf)[1];
  1306.  
  1307.                     teIn   = (*frHndl)->doc.message[kMessageIn];
  1308.                     intxt  = (*teIn)->hText;
  1309.  
  1310.                     txFont = curPort->txFont;
  1311.                     txSize = curPort->txSize;
  1312.                     txFace = curPort->txFace;
  1313.                     TextFont(styl.tsFont);
  1314.                     TextSize((*(short **)finf)[3]);
  1315.                     TextFace(normal);
  1316.                     outtxt = CTESwapText(teOut, NewHandle(0), nil, true);
  1317.                     TextFont(txFont);
  1318.                     TextSize(txSize);
  1319.                     TextFace(txFace);
  1320.  
  1321.                     inlen  = (*teIn)->teLength;
  1322.                     outlen = GetHandleSize(outtxt);
  1323.  
  1324.                     GetClip(oldClip = NewRgn());
  1325.                     SetClip(newClip = NewRgn());
  1326.  
  1327.                     overflow = inlen + outlen - 31998;
  1328.                     if (overflow > 0) {
  1329.                         if (overflow > inlen) overflow = inlen;
  1330.                         TESetSelect(0, overflow, teIn);
  1331.                         TEDelete(teIn);
  1332.                         inlen -= overflow;
  1333.                     }
  1334.  
  1335.                     inlen = (*teIn)->teLength;
  1336.                     TESetSelect(inlen, inlen, teIn);
  1337.                     if ((inlen) && (outlen < 31998)) {
  1338.                         i = ((*intxt)[inlen - 1] == 13) ? 1 : 2;
  1339.                         for (;i--;) {
  1340.                             TEKey(13, teIn);
  1341.                             ++inlen;
  1342.                         }
  1343.                         styl.tsSize = 4;
  1344.                         TESetSelect(inlen - 1, inlen, teIn);
  1345.                         TESetStyle((doFont | doSize), &styl, false, teIn);
  1346.                         TESetSelect(inlen, inlen, teIn);
  1347.                     }
  1348.  
  1349.                     HLock(outtxt);
  1350.                     TEInsert(*outtxt, outlen, teIn);
  1351.                     DisposeHandle(outtxt);
  1352.  
  1353.                     TESetSelect(inlen, (*teIn)->teLength, teIn);
  1354.  
  1355.                     styl.tsFace = italic;
  1356.                     styl.tsSize = 9;
  1357.                     TESetStyle((doFont | doFace | doSize), &styl, false, teIn);
  1358.  
  1359.                     TECalText(teIn);
  1360.                     pt = TEGetPoint(inlen, teIn);
  1361.                     pt.v -= 12;
  1362.                     TEScroll(0, (*teIn)->viewRect.top - pt.v, teIn);
  1363.  
  1364.                     SetClip(oldClip);
  1365.                     DisposeRgn(oldClip);
  1366.                     DisposeRgn(newClip);
  1367.  
  1368.                     CTEUpdate(teIn, CTEViewFromTE(teIn), false);
  1369.                     CTEAdjustTEBottom(teIn);
  1370.                     CTEAdjustScrollValues(teIn);
  1371.  
  1372.                     break;
  1373.  
  1374.                 case kSoundMssg:
  1375.                     SndPlay(nil, (*frHndl)->doc.sound, false);
  1376.                     break;
  1377.             }
  1378.         }
  1379.  
  1380.         AEDisposeDesc(&theAevt);
  1381.         AEDisposeDesc(&reply);
  1382.             /* Dispose of the descriptors, created or not.
  1383.             ** If not created, no harm done by calling. */
  1384.     }
  1385.  
  1386.     SetPort(oldPort);
  1387.     return(err);
  1388. }
  1389.  
  1390.  
  1391.  
  1392. /*****************************************************************************/
  1393.  
  1394.  
  1395.  
  1396. pascal OSErr    ReceiveMssg(AppleEvent *message, AppleEvent *reply, long refcon)
  1397. {
  1398. #ifndef __MWERKS__
  1399. #pragma unused (refcon)
  1400. #endif
  1401.  
  1402.     OSErr            err;
  1403.     long            gameID[2], time[2];
  1404.     short            messageType, i, inlen, outlen, overflow;
  1405.     WindowPtr        oldPort, window;
  1406.     FileRecHndl        frHndl;
  1407.     DescType        actualType;
  1408.     long            actualSize, mssgSize;
  1409.     unsigned long    key;
  1410.     char            hstate;
  1411.     Handle            mssgData, intxt, outtxt;
  1412.     AEAddressDesc    locOfOpponent;
  1413.     RgnHandle        oldClip, newClip;
  1414.     TEHandle        teIn;
  1415.     TextStyle        styl;
  1416.     Point            pt;
  1417.     Handle            finf;
  1418.  
  1419.     err = noErr;
  1420.     AEPutParamPtr(                /* RETURN REPLY ERROR, EVEN IF NONE... */
  1421.         reply,                    /* The AppleEvent.              */
  1422.         keyReplyErr,            /* AEKeyword                 */
  1423.         typeShortInteger,        /* Desired type.             */
  1424.         (Ptr)&err,                /* Pointer to area for data. */ 
  1425.         sizeof(short)            /* Size of data area.         */
  1426.     );
  1427.  
  1428.     err = AEGetParamPtr(        /* GET THE MESSAGE TYPE.     */
  1429.         message,                /* The AppleEvent.              */
  1430.         keyDirectObject,        /* AEKeyword                 */
  1431.         typeShortInteger,        /* Desired type.             */
  1432.         &actualType,            /* Type code.                 */
  1433.         (Ptr)&messageType,        /* Pointer to area for data. */ 
  1434.         2 * sizeof(long),        /* Size of data area.         */
  1435.         &actualSize                /* Returned size of data.     */
  1436.     );
  1437.  
  1438.     if (!err) {
  1439.         err = AEGetParamPtr(        /* GET WINDOW MESSAGE IS FOR. */
  1440.             message,                /* The AppleEvent.               */
  1441.             keyGameID,                /* AEKeyword                  */
  1442.             typeDoubleLong,            /* Desired type.              */
  1443.             &actualType,            /* Type code.                  */
  1444.             (Ptr)&gameID[0],        /* Pointer to area for data.  */ 
  1445.             2 * sizeof(long),        /* Size of data area.          */
  1446.             &actualSize                /* Returned size of data.      */
  1447.         );
  1448.     }
  1449.  
  1450.     if (!err) {            /* See if the requested window exists... */
  1451.         window = GetGameWindow(gameID[1], gameID[0]);
  1452.         if (window) {
  1453.             frHndl = (FileRecHndl)GetWRefCon(window);
  1454.                 /* The game still exists... */
  1455.         }
  1456.         else
  1457.             err = userCanceledErr;
  1458.                 /* User (or computer) canceled game by disconnecting improperly. */
  1459.     }
  1460.  
  1461.     if (!err) {        /* If everything is cool, then do the specific task... */
  1462.  
  1463.         switch(messageType) {
  1464.  
  1465.             case kAmWhiteMssg:
  1466.             case kAmBlackMssg:
  1467.                 messageType ^= 1;
  1468.                 (*frHndl)->doc.configColor       = messageType;
  1469.                 (*frHndl)->doc.configColorChange = true;
  1470.                 (*frHndl)->doc.resync            = kHandResync;
  1471.                 if ((*frHndl)->doc.creator)
  1472.                     SendMssg(frHndl, messageType);
  1473.                         /* If we are the creator, echo the message to make sure
  1474.                         ** that both players aren't the same color. */
  1475.                 break;
  1476.  
  1477.             case kDisconnectMssg:
  1478.                 locOfOpponent = (*frHndl)->doc.locOfOpponent;
  1479.                 AEDisposeDesc(&locOfOpponent);
  1480.                 (*frHndl)->doc.twoPlayer = kLimbo;
  1481.                     /* We set the state of the game to NOT two-player, and NOT
  1482.                     ** what we are now.  This allows us to call SetOpponentType
  1483.                     ** to do all the work we need done.  If we didn't fudge the
  1484.                     ** state of the game (from two-player) then SetOpponentType
  1485.                     ** would send a disconnect message (and we would end up
  1486.                     ** back here.)  This would be an ugly situation, which is
  1487.                     ** completely prevented by fudging the state of the game. */
  1488.                 SetOpponentType(frHndl, kOnePlayer);
  1489.                 break;
  1490.  
  1491.             case kTimeMssg:
  1492.                 AEGetParamPtr(
  1493.                     message,                /* The AppleEvent.              */
  1494.                     keyTime,                /* AEKeyword                 */
  1495.                     typeDoubleLong,            /* Desired type.             */
  1496.                     &actualType,            /* Type code.                 */
  1497.                     (Ptr)&time[0],            /* Pointer to area for data. */ 
  1498.                     2 * sizeof(long),        /* Size of data area.         */
  1499.                     &mssgSize                /* Returned size of data.     */
  1500.                 );
  1501.                 for (i = 0; i < 2; ++i)
  1502.                     (*frHndl)->doc.configTime[i] = time[i];
  1503.                 if ((*frHndl)->doc.resync)
  1504.                     (*frHndl)->doc.configTimeChange = true;
  1505.                 else {
  1506.                     for (i = 0; i < 2; ++i)
  1507.                         (*frHndl)->doc.timeLeft[i] =
  1508.                             (*frHndl)->doc.displayTime[i] = time[i];
  1509.                     UpdateTime(frHndl, false);
  1510.                     DrawTime(frHndl);
  1511.                 }
  1512.                 if ((*frHndl)->doc.creator)
  1513.                     SendMssg(frHndl, kTimeMssg);
  1514.                         /* If we are the creator, echo the message to make sure
  1515.                         ** the clocks are in sync. */
  1516.                 break;
  1517.  
  1518.             case kTextMssg:
  1519.             case kSoundMssg:
  1520.                 /* Both the text and sound message simply send a block of
  1521.                 ** data less than 32k.  Get the data from the AppleEvent
  1522.                 ** for both cases, and then decide what kind of data it is. */
  1523.  
  1524.                 key = (messageType == kTextMssg) ? keyTextMessage : keySoundMessage;
  1525.                 if (!err) {        /* Determine the size of the data... */
  1526.                     err = AEGetParamPtr(
  1527.                         message,                /* The AppleEvent.              */
  1528.                         key,                    /* AEKeyword                 */
  1529.                         typeMssg,                /* Desired type.             */
  1530.                         &actualType,            /* Type code.                 */
  1531.                         nil,                    /* Pointer to area for data. */ 
  1532.                         0,                        /* Size of data area.         */
  1533.                         &mssgSize                /* Returned size of data.     */
  1534.                     );
  1535.                 }
  1536.                 mssgData = nil;
  1537.                 if (!err) {        /* Get the data... */
  1538.                     mssgData = NewHandle(mssgSize);
  1539.                     if (mssgData) {
  1540.                         hstate = LockHandleHigh(mssgData);
  1541.                         err = AEGetParamPtr(
  1542.                             message,                /* The AppleEvent.              */
  1543.                             key,                    /* AEKeyword                 */
  1544.                             typeMssg,                /* Desired type.             */
  1545.                             &actualType,            /* Type code.                 */
  1546.                             *mssgData,                /* Pointer to area for data. */ 
  1547.                             mssgSize,                /* Size of data area.         */
  1548.                             &actualSize                /* Returned size of data.     */
  1549.                         );
  1550.                     }
  1551.                     else err = memFullErr;
  1552.                 }
  1553.                 if (!err) {
  1554.                     if (messageType == kTextMssg) {
  1555.  
  1556.                         finf = GetResource('finf', 128);
  1557.                         styl.tsFont = (*(short **)finf)[1];
  1558.  
  1559.                         teIn   = (*frHndl)->doc.message[kMessageIn];
  1560.                         intxt  = (*teIn)->hText;
  1561.                         outtxt = mssgData;
  1562.                         inlen  = (*teIn)->teLength;
  1563.                         outlen = GetHandleSize(outtxt);
  1564.  
  1565.                         oldPort = SetFilePort(frHndl);
  1566.                         GetClip(oldClip = NewRgn());
  1567.                         SetClip(newClip = NewRgn());
  1568.  
  1569.                         overflow = inlen + outlen - 31998;
  1570.                         if (overflow > 0) {
  1571.                             if (overflow > inlen) overflow = inlen;
  1572.                             TESetSelect(0, overflow, teIn);
  1573.                             TEDelete(teIn);
  1574.                             inlen -= overflow;
  1575.                         }
  1576.  
  1577.                         inlen = (*teIn)->teLength;
  1578.                         TESetSelect(inlen, inlen, teIn);
  1579.                         if ((inlen) && (outlen < 31998)) {
  1580.                             i = ((*intxt)[inlen - 1] == 13) ? 1 : 2;
  1581.                             for (;i--;) {
  1582.                                 TEKey(13, teIn);
  1583.                                 ++inlen;
  1584.                             }
  1585.                             styl.tsSize = 4;
  1586.                             TESetSelect(inlen - 1, inlen, teIn);
  1587.                             TESetStyle((doFont | doSize), &styl, false, teIn);
  1588.                             TESetSelect(inlen, inlen, teIn);
  1589.                         }
  1590.  
  1591.                         HLock(outtxt);
  1592.                         TEInsert(*outtxt, outlen, teIn);
  1593.  
  1594.                         TESetSelect(inlen, (*teIn)->teLength, teIn);
  1595.  
  1596.                         styl.tsFace = normal;
  1597.                         styl.tsSize = (*(short **)finf)[3];
  1598.                         TESetStyle((doFont | doFace | doSize), &styl, false, teIn);
  1599.  
  1600.                         TECalText(teIn);
  1601.                         pt = TEGetPoint(inlen, teIn);
  1602.                         pt.v -= 12;
  1603.                         TEScroll(0, (*teIn)->viewRect.top - pt.v, teIn);
  1604.  
  1605.                         SetClip(oldClip);
  1606.                         DisposeRgn(oldClip);
  1607.                         DisposeRgn(newClip);
  1608.                         SetPort(oldPort);
  1609.  
  1610.                         CTEUpdate(teIn, CTEViewFromTE(teIn), false);
  1611.                         CTEAdjustTEBottom(teIn);
  1612.                         CTEAdjustScrollValues(teIn);
  1613.  
  1614.                         if ((*frHndl)->doc.doSpeech)
  1615.                             SayText(teIn, nil, (*frHndl)->doc.theVoice);
  1616.  
  1617.                         if (GetControlValue((*frHndl)->doc.beepOnMssg))
  1618.                             if (mssgSize) SysBeep(1);
  1619.                     }
  1620.                     else SndPlay(nil, mssgData, false);
  1621.                 }
  1622.                 if (mssgData) DisposeHandle(mssgData);
  1623.                 if (!err) NotifyUser();
  1624.                 break;
  1625.  
  1626.             case kBeepMssg:
  1627.                 SysBeep(1);
  1628.                 break;
  1629.  
  1630.         }
  1631.     }
  1632.  
  1633.     return(err);
  1634. }
  1635.  
  1636.  
  1637.  
  1638. /*****************************************************************************/
  1639. /*****************************************************************************/
  1640.  
  1641.  
  1642.  
  1643. /* GetGameWindow
  1644. **
  1645. ** Find the window with the specified game ID's. */
  1646.  
  1647. WindowPtr    GetGameWindow(long gameID_0, long gameID_1)
  1648. {
  1649.     WindowPeek    window;
  1650.     FileRecHndl    frHndl;
  1651.  
  1652.     for (window = LMGetWindowList(); window; window = window->nextWindow) {
  1653.         if (IsAppWindow((WindowPtr)window)) {
  1654.             frHndl = (FileRecHndl)GetWRefCon((WindowPtr)window);
  1655.             if (
  1656.                 ((*frHndl)->doc.gameID_0 == gameID_0) &&
  1657.                 ((*frHndl)->doc.gameID_1 == gameID_1)
  1658.             ) return((WindowPtr)window);
  1659.         }
  1660.     }
  1661.  
  1662.     return(nil);
  1663. }
  1664.  
  1665.  
  1666.  
  1667. /*****************************************************************************/
  1668.  
  1669.  
  1670.  
  1671. /* KibitzPortFilter
  1672. **
  1673. ** Don't allow PPCBrowser to show any applications other than Kibitz. */
  1674.  
  1675. pascal Boolean    KibitzPortFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
  1676. {
  1677. #ifndef __MWERKS__
  1678. #pragma unused (locationName)
  1679. #endif
  1680.  
  1681.     long    type;
  1682.  
  1683.     if (thePortInfo->name.portKindSelector == ppcByString) {
  1684.         BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  1685.             /* The BlockMove is so that we don't get an address error
  1686.             ** on a 68000-based machine due to referencing a long at
  1687.             ** an odd-address. */
  1688.         if (type == gameCreator) return(true);
  1689.     }
  1690.  
  1691.     return(false);
  1692. }
  1693.  
  1694.  
  1695.  
  1696. /*****************************************************************************/
  1697.  
  1698.  
  1699.  
  1700. /* SetOpponentType
  1701. **
  1702. ** Change the opponent type from whatever it currently is to the specified
  1703. ** type.  In so doing, change the state of any controls, etc., that need
  1704. ** to be changed due to the new opponent type. */
  1705.  
  1706. void    SetOpponentType(FileRecHndl frHndl, short newOpponentType)
  1707. {
  1708.     WindowPtr        oldPort, window;
  1709.     short            oldOpponentType, hilite, i, toggle;
  1710.     AEAddressDesc    locOfOpponent;
  1711.     Rect            boardRect;
  1712.     ControlHandle    ctl;
  1713.     RgnHandle        oldClip, newClip;
  1714.  
  1715.     if (!(*frHndl)->fileState.window) return;
  1716.  
  1717.     if (!(oldOpponentType = (*frHndl)->doc.arrangeBoard))
  1718.         oldOpponentType = (*frHndl)->doc.twoPlayer;
  1719.  
  1720.     if (oldOpponentType == newOpponentType) return;
  1721.  
  1722.     (*frHndl)->doc.arrangeBoard = false;
  1723.  
  1724.     oldPort = SetFilePort(frHndl);
  1725.     GetPort(&window);
  1726.  
  1727.     oldClip = NewRgn();
  1728.     newClip = NewRgn();
  1729.     GetClip(oldClip);
  1730.  
  1731.     toggle = false;
  1732.     if ((newOpponentType == kArrangeBoard) || (oldOpponentType == kArrangeBoard)) {
  1733.         toggle = true;
  1734.         SetClip(newClip);        /* Prevent stuff from drawing. */
  1735.     }
  1736.  
  1737.     if (oldOpponentType == kTwoPlayer) {
  1738.         SendMssg(frHndl, kDisconnectMssg);
  1739.         locOfOpponent = (*frHndl)->doc.locOfOpponent;
  1740.         AEDisposeDesc(&locOfOpponent);
  1741.     }
  1742.  
  1743.     if (newOpponentType == kTwoPlayer) {
  1744.         hilite = 0;
  1745.         (*frHndl)->doc.timerRefTick = TickCount();
  1746.         (*frHndl)->doc.creator = true;
  1747.         if ((*frHndl)->doc.myColor == WHITE) (*frHndl)->doc.compMovesBlack = false;
  1748.         else                                 (*frHndl)->doc.compMovesWhite = false;
  1749.     }
  1750.     else {
  1751.         hilite = 255;
  1752.         (*frHndl)->doc.creator = false;
  1753.         (*frHndl)->doc.resync  = kIsMove;
  1754.         (*frHndl)->doc.gameID_0 = (*frHndl)->doc.gameID_1 = 0;
  1755.     }
  1756.  
  1757.     SetPort(window);
  1758.  
  1759.     if (newOpponentType == kArrangeBoard) {
  1760.         CTEActivate(false, CTEFindActive(window));
  1761.         (*frHndl)->doc.king[BLACK].rookMoves[QSIDE] = 0;
  1762.         (*frHndl)->doc.king[BLACK].rookMoves[KSIDE] = 0;
  1763.         (*frHndl)->doc.king[WHITE].rookMoves[QSIDE] = 0;
  1764.         (*frHndl)->doc.king[WHITE].rookMoves[KSIDE] = 0;
  1765.         (*frHndl)->doc.enPasMove        = 0;
  1766.         (*frHndl)->doc.enPasPawnLoc     = 0;
  1767.         (*frHndl)->doc.arngEnPasMove    = 0;
  1768.         (*frHndl)->doc.arngEnPasPawnLoc = 0;
  1769.         (*frHndl)->doc.numLegalMoves    = 0;
  1770.         (*frHndl)->doc.gameIndex        = 0;
  1771.         (*frHndl)->doc.numGameMoves     = 0;
  1772.         (*frHndl)->doc.compMovesWhite   = false;
  1773.         (*frHndl)->doc.compMovesBlack   = false;
  1774.         AdjustGameSlider(frHndl);
  1775.     }
  1776.     if (oldOpponentType == kArrangeBoard) CTEWindActivate(window, true);
  1777.  
  1778.     if (newOpponentType == kArrangeBoard) {
  1779.         (*frHndl)->doc.arrangeBoard = kArrangeBoard;
  1780.         newOpponentType = kOnePlayer;
  1781.     }
  1782.     (*frHndl)->doc.twoPlayer = newOpponentType;
  1783.  
  1784.     HiliteControl(ctl = (*frHndl)->doc.sendMessage, hilite);
  1785.     OutlineControl(ctl);
  1786.     HiliteControl((*frHndl)->doc.beepOnMove, hilite);
  1787.     HiliteControl((*frHndl)->doc.beepOnMssg, hilite);
  1788.  
  1789.     if (!SoundInputAvaliable()) hilite = 255;
  1790.     HiliteControl((*frHndl)->doc.record, hilite);
  1791.     if (!(*frHndl)->doc.sound) hilite = 255;
  1792.     HiliteControl((*frHndl)->doc.sendSnd, hilite);
  1793.     DrawButtonTitle(frHndl, newOpponentType);
  1794.  
  1795.     if (toggle) {
  1796.         SetClip(oldClip);
  1797.         for (i = 0; i < 2; ++i) (*frHndl)->doc.timeLeft[i] = -1;
  1798.         boardRect = BoardRect();
  1799.         boardRect.left = boardRect.right + 1;
  1800.         boardRect.right = 1000;
  1801.         EraseRect(&boardRect);
  1802.         ImageDocument(frHndl, false);
  1803.     }
  1804.  
  1805.     DisposeRgn(oldClip);
  1806.     DisposeRgn(newClip);
  1807.     SetPort(oldPort);
  1808. }
  1809.  
  1810.  
  1811.  
  1812. /*****************************************************************************/
  1813.  
  1814.  
  1815.  
  1816. void    GetFullPathAndAppName(StringPtr path, StringPtr app)
  1817. {
  1818.     ProcessSerialNumber    psn;
  1819.     ProcessInfoRec        pinfo;
  1820.     FSSpec                fss;
  1821.  
  1822.     pinfo.processInfoLength = sizeof(ProcessInfoRec);
  1823.     pinfo.processName       = app;
  1824.     pinfo.processAppSpec    = &fss;
  1825.  
  1826.     psn.lowLongOfPSN  = kCurrentProcess;
  1827.     psn.highLongOfPSN = kNoProcess;
  1828.     GetProcessInformation(&psn, &pinfo);
  1829.  
  1830.     PathNameFromDirID(pinfo.processAppSpec->parID, pinfo.processAppSpec->vRefNum, path);
  1831. }
  1832.  
  1833.  
  1834.  
  1835. /*****************************************************************************/
  1836.  
  1837.  
  1838.  
  1839. /* Don't allow DoIPCListPorts to find anything but the finder. */
  1840.  
  1841. pascal Boolean    FinderFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
  1842. {
  1843. #ifndef __MWERKS__
  1844. #pragma unused (locationName)
  1845. #endif
  1846.  
  1847.     OSType    type;
  1848.  
  1849.     if (thePortInfo->name.portKindSelector == ppcByString) {
  1850.         BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  1851.             /* The BlockMove is so that we don't get an address error
  1852.             ** on a 68000-based machine due to referencing a long at
  1853.             ** an odd-address. */
  1854.         if (type == 'MACS') return(true);
  1855.     }
  1856.  
  1857.     return(false);
  1858. }
  1859.  
  1860. /***/
  1861.  
  1862. /* Don't allow DoIPCListPorts to find anything but Kibitz. */
  1863.  
  1864. static pascal Boolean    KibitzFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
  1865. {
  1866. #ifndef __MWERKS__
  1867. #pragma unused (locationName)
  1868. #endif
  1869.  
  1870.     OSType    type;
  1871.  
  1872.     if (thePortInfo->name.portKindSelector == ppcByString) {
  1873.         BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  1874.             /* The BlockMove is so that we don't get an address error
  1875.             ** on a 68000-based machine due to referencing a long at
  1876.             ** an odd-address. */
  1877.         if (type == 'KBTZ') return(true);
  1878.     }
  1879.  
  1880.     return(false);
  1881. }
  1882.  
  1883. /***/
  1884.  
  1885. OSErr    GetRemoteProcessTarget(FileRecHndl frHndl, AEDesc *retDesc, GRPTProcPtr proc)
  1886. {
  1887.     OSErr            err;
  1888.     char            hstate;
  1889.     PortInfoRec        info;        /* Just one, please. */
  1890.     LocationNameRec    loc;
  1891.     short            indx, reqCount, actCount;
  1892.     TargetID        theID;
  1893.  
  1894.     retDesc->dataHandle = nil;        /* So caller can dispose always. */
  1895.  
  1896.     hstate = LockHandleHigh((Handle)frHndl);
  1897.     loc.locationKindSelector = ppcNBPLocation;        /* Using an NBP construct. */
  1898.     pcpy(loc.u.nbpEntity.objStr,  (*frHndl)->doc.reconnectMachine);
  1899.     pcpy(loc.u.nbpEntity.zoneStr, (*frHndl)->doc.reconnectZone);
  1900.     pcpy(loc.u.nbpEntity.typeStr, "\pPPCToolBox");
  1901.     HSetState((Handle)frHndl, hstate);
  1902.  
  1903.     indx     = 0;
  1904.     reqCount = 1;
  1905.     actCount = 0;
  1906.     err = DoIPCListPorts(&indx, &reqCount, &actCount, &loc, &info, proc);
  1907.     if (err) return(err);
  1908.  
  1909.     if (actCount) {
  1910.         theID.name = info.name;
  1911.         theID.location = loc;
  1912.         err = AECreateDesc(typeTargetID, (Ptr)&theID, sizeof(theID), retDesc);
  1913.     }
  1914.  
  1915.     return(err);
  1916. }
  1917.  
  1918.  
  1919.  
  1920.